package com.csap.framework.apidoc.service;

import com.csap.framework.annotation.EnumMessage;
import com.csap.framework.annotation.apidoc.ApiProperty;
import com.csap.framework.annotation.apidoc.ApiPropertys;
import com.csap.framework.apidoc.model.CsapDocMethod;
import com.csap.framework.apidoc.model.CsapDocModel;
import com.csap.framework.apidoc.model.CsapDocModelController;
import com.csap.framework.apidoc.model.CsapDocParameter;
import com.csap.framework.properties.apidoc.ModelType;
import com.csap.framework.properties.apidoc.ModelTypepProperties;
import com.csap.framework.util.ClazzUtils;
import com.csap.framework.util.CollectionsUtil;
import com.csap.framework.util.TypeVariableModel;
import com.csap.mybatisplus.annotation.EnumValue;
import com.csap.mybatisplus.annotation.TableName;
import com.csap.mybatisplus.core.toolkit.ReflectionKit;
import com.google.common.collect.Lists;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author yangchengfu
 * @description
 * @dataTime 2021年-01月-22日 15:32:00
 **/
public interface FilterData {

    /**
     * 查询单参数的属性注解
     *
     * @param method 方法
     * @param name   名称
     * @return
     */
    default ApiProperty apiPropertys(Method method, String name) {
        ApiPropertys annotations = method.getAnnotation(ApiPropertys.class);
        if (annotations == null) {
            return apiProperty(method.getAnnotation(ApiProperty.class), name);
        } else {
            for (ApiProperty apiProperty : annotations.value()) {
                ApiProperty property = apiProperty(apiProperty, name);
                if (property != null) {
                    return property;
                }
            }
        }
        return null;
    }

    /**
     * 过滤对应表
     *
     * @param cl     api属性
     * @param string 表名称
     * @return true/false
     */
    default boolean filterTable(Class cl, String string) {
        Type type = cl.getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            Class<?> aClass = (Class<?>) parameterizedType.getActualTypeArguments()[1];
            if (aClass.isAnnotationPresent(TableName.class)) {
                return string.equals(aClass.getAnnotation(TableName.class).value());
            }
        }
        return false;
    }

    /**
     * 方法返回数据类型【基本数据类型处理方案】
     *
     * @param typepProperties
     * @return
     */
    default CsapDocModel methodReturnBasicType(ModelTypepProperties typepProperties, CsapDocMethod docMethod) {
        return CsapDocModel.builder()
                .modelType(ModelType.BASE_DATA)
                .name(typepProperties.getCl().getName())
                .parameters(Arrays.asList(CsapDocParameter.builder()
                        .dataType(typepProperties.getSubStr())
                        .name(typepProperties.getSubStr())
                        .required(true)
                        .group(docMethod.getGroup())
                        .version(docMethod.getVersion())
                        .value(typepProperties.getSubStr())
                        .build()))
                .build();
    }

    /**
     * 获取单属性匹配的注解
     *
     * @param apiProperty
     * @param name
     * @return
     */
    default ApiProperty apiProperty(ApiProperty apiProperty, String name) {
        if (apiProperty == null || apiProperty.hidden()) {
            return null;
        }
        if (name.equals(apiProperty.name())) {
            return apiProperty;
        }
        return null;
    }

    /**
     * 处理枚举类型数据
     *
     * @param type
     */
    default List<Map<String, String>> enumData(Class<?> type) {
        List<Map<String, String>> list = Lists.newArrayList();
        if (Enum.class.isAssignableFrom(type)) {
            Enum[] es = (Enum[]) type.getEnumConstants();
            for (Enum e : es) {
                Map<String, String> map = new HashMap<>(16);
                for (Field f : type.getDeclaredFields()) {
                    if (f.isAnnotationPresent(EnumValue.class) || f.isAnnotationPresent(EnumMessage.class)) {
                        Method method = ReflectionKit.getMethod(type, f);
                        try {
                            map.put(f.getName(), method.invoke(e).toString());
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }
                }
                if (!map.isEmpty()) {
                    list.add(map);
                }
            }
        }
        return list;
    }

    /**
     * 过滤字段具体类型
     *
     * @param types
     * @param field
     * @param typeVariableModel
     * @return
     */
    default ModelTypepProperties getFildType(List<Type> types, Field field, TypeVariableModel typeVariableModel) {
        Type type = field.getGenericType();
        if (CollectionsUtil.isNotEmpty(types)) {
            if ((type instanceof TypeVariable || (type instanceof ParameterizedType))) {
                TypeVariable<? extends Class<?>>[] typeVariables = field.getDeclaringClass().getTypeParameters();
                if (CollectionsUtil.isNotEmpty(typeVariables)) {
                    int x = 0;
                    Type[] typeVariable = new Type[]{type};
                    if (type instanceof ParameterizedType) {
                        typeVariable = ((ParameterizedType) type).getActualTypeArguments();
                    }
                    if (typeVariable.length == 1 && typeVariable[0] instanceof Class) {
                        return ClazzUtils.getRawClassType(typeVariable[0], typeVariableModel);
                    }
                    for (int i = 0; i < typeVariables.length; i++) {
                        if (typeVariables[i].getName().equals(typeVariable[i].getTypeName())) {
                            x = i;
                            break;
                        }
                    }
                    return ClazzUtils.getRawClassType(types.get(x), typeVariableModel);
                }
            }
        }
        return ClazzUtils.getRawClassType(type, typeVariableModel);
    }

    default String getKey(CsapDocParameter docParameter) {
        return System.nanoTime() + Integer.toHexString(System.identityHashCode(docParameter));
    }
}
